﻿using System.Collections.Generic;
using Properties;

namespace BorgExt
{
    public class DiscoveryCore : RuntimeElement
    {
        public TypeBuilder TypeBuilder { get; private set; }

        protected internal DiscoveryCore()
        { }

        protected override void Init()
        {
            TypeBuilder = new TypeBuilder(Runtime);
        }

        public void AssemblyDiscovered(DiscoveryEventArgs args)
        {
            if (Runtime.Dispatcher.CheckAccess())
                InternalAssemblyDiscovered(args);
            else
                Invoke(InternalAssemblyDiscovered, new object[] { args });
        }

        public void AssemblyRemoved(DiscoveryEventArgs args)
        {
            if (Runtime.Dispatcher.CheckAccess())
                InternalAssemblyRemoved(args);
            else
                Invoke(InternalAssemblyRemoved, new object[] { args });
        }

        private void Invoke(DiscoveryEventHandler handler, params object[] args)
        {
            Runtime.Dispatcher.Invoke(handler, args);
        }

        private void InternalAssemblyDiscovered(DiscoveryEventArgs args)
        {
            if (args.Contracts != null)
                LogContractDiscovered(args.Contracts);
            
            if (args.Plugins != null)
                LogPluginDiscovered(args.Plugins);
            
            TypeStore.Modifier.Add(args.Contracts, args.Plugins);
        }

        private void InternalAssemblyRemoved(DiscoveryEventArgs args)
        {
            if (args.Contracts != null)
                LogContractRemoved(args.Contracts);
            
            if (args.Plugins != null)
                LogPluginRemoved(args.Plugins);
            
            TypeStore.Modifier.Remove(args.Contracts, args.Plugins);
        }

        private void LogContractDiscovered(IEnumerable<Contract> contracts)
        {
            foreach (var contract in contracts)
            {
                Logger.OnLog(
                    this,
                    Messages.Discovery_AssemblyDiscovered,
                    (object) "Contract",
                    (object) contract.Id,
                    (object) contract.Name,
                    (object) contract.Uri);
                
                foreach (var slotDefinition in contract.SlotDefinitions)
                    Logger.OnLog(
                        VerbosityLevel.Diagnostic,
                        this,
                        Messages.Discovery_ElementFound,
                        (object) "Slot definition",
                        (object) slotDefinition.Id,
                        (object) slotDefinition.Name);
            }
        }

        private void LogPluginDiscovered(IEnumerable<Plugin> plugins)
        {
            foreach (var plugin in plugins)
            {
                Logger.OnLog(
                    this,
                    Messages.Discovery_AssemblyDiscovered,
                    (object) "Plugin",
                    (object) plugin.Id,
                    (object) plugin.Name,
                    (object) plugin.Uri);
                
                foreach (var extensionType in plugin.ExtensionTypes)
                {
                    Logger.OnLog(
                        VerbosityLevel.Diagnostic,
                        this,
                        Messages.Discovery_ElementFound,
                        (object) "Extension type",
                        (object) extensionType.Id,
                        (object) extensionType.Name);
                    
                    foreach (var plugType in extensionType.PlugTypes)
                        Logger.OnLog(
                            VerbosityLevel.Diagnostic,
                            this,
                            Messages.Discovery_ElementFound,
                            (object) "Plug type",
                            (object) plugType.Id,
                            (object) plugType.Name);
                    
                    foreach (var slotType in extensionType.SlotTypes)
                        Logger.OnLog(
                            VerbosityLevel.Diagnostic,
                            this,
                            Messages.Discovery_ElementFound,
                            (object) "Slot type",
                            (object) slotType.Id,
                            (object) slotType.Name);
                }
            }
        }

        private void LogContractRemoved(IEnumerable<Contract> contracts)
        {
            foreach (var contract in contracts)
            {
                Logger.OnLog(
                    this,
                    Messages.Discovery_AssemblyRemoved,
                    (object)"Contract",
                    (object)contract.Id,
                    (object)contract.Name,
                    (object)contract.Uri);
                
                foreach (var slotDefinition in contract.SlotDefinitions)
                    Logger.OnLog(
                        VerbosityLevel.Diagnostic,
                        this,
                        Messages.Discovery_ElementRemoved,
                        (object)"Slot definition",
                        (object)slotDefinition.Id,
                        (object)slotDefinition.Name);
            }
        }

        private void LogPluginRemoved(IEnumerable<Plugin> plugins)
        {
            foreach (var plugin in plugins)
            {
                Logger.OnLog(
                    this,
                    Messages.Discovery_AssemblyRemoved,
                    (object) "Plugin",
                    (object) plugin.Id,
                    (object) plugin.Name,
                    (object) plugin.Uri);
                
                foreach (var extensionType in plugin.ExtensionTypes)
                {
                    Logger.OnLog(
                        VerbosityLevel.Diagnostic,
                        this,
                        Messages.Discovery_ElementRemoved,
                        (object) "Extension type",
                        (object) extensionType.Id,
                        (object) extensionType.Name);
                    
                    foreach (var plugType in extensionType.PlugTypes)
                        Logger.OnLog(
                            VerbosityLevel.Diagnostic,
                            this,
                            Messages.Discovery_ElementRemoved,
                            (object) "Plug type",
                            (object) plugType.Id,
                            (object) plugType.Name);
                    
                    foreach (var slotType in extensionType.SlotTypes)
                        Logger.OnLog(
                            VerbosityLevel.Diagnostic,
                            this,
                            Messages.Discovery_ElementRemoved,
                            (object) "Slot type",
                            (object) slotType.Id,
                            (object) slotType.Name);
                }
            }
        }
    }
}

